package com.mldong.modules.sys.provider;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.lang.Dict;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.mldong.modules.sys.api.TaskExecutionApi;
import com.mldong.modules.sys.dto.TaskExecutionQueueDTO;
import com.mldong.modules.sys.entity.TaskExecutionHistory;
import com.mldong.modules.sys.entity.TaskExecutionQueue;
import com.mldong.modules.sys.enums.TaskExecutionHistoryStateEnum;
import com.mldong.modules.sys.enums.TaskExecutionQueueStateEnum;
import com.mldong.modules.sys.mapper.TaskExecutionHistoryMapper;
import com.mldong.modules.sys.mapper.TaskExecutionQueueMapper;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import java.util.Date;
import java.util.List;

@Component
@RequiredArgsConstructor
public class TaskExecutionProvider implements TaskExecutionApi {
    private final TaskExecutionQueueMapper taskExecutionQueueMapper;
    private final TaskExecutionHistoryMapper taskExecutionHistoryMapper;

    @Override
    public Long addTaskToQueue(String taskName, Class<?> springBeanClass, Long bizId, Integer allowMaxErrorCount, Dict ext) {
        TaskExecutionQueue queue = new TaskExecutionQueue();
        queue.setTaskName(taskName);
        String springBeanName = springBeanClass.getSimpleName();
        queue.setSpringBeanName(StrUtil.lowerFirst(springBeanName));
        queue.setBizId(bizId);
        queue.setAllowMaxErrorCount(allowMaxErrorCount);
        queue.setTaskState(TaskExecutionQueueStateEnum.NOT_STARTED.getCode());
        queue.setErrorCount(0);
        // 确保 variable 字段始终有默认值
        if (ext != null && !ext.isEmpty()) {
            queue.setVariable(JSONUtil.toJsonStr(ext));
        } else {
            queue.setVariable("{}"); // 默认空JSON对象
        }
        taskExecutionQueueMapper.insert(queue);
        return queue.getId();
    }

    @Override
    @Transactional(propagation = Propagation.REQUIRES_NEW)
    public boolean updateTaskState(Long taskId, Integer taskState, String errorReason) {
        TaskExecutionQueue queue = new TaskExecutionQueue();
        queue.setId(taskId);
        queue.setTaskState(taskState);
        if (errorReason != null) {
            queue.setErrorReason(errorReason);
        }
        queue.setLatestExecutionTime(new Date());
        return taskExecutionQueueMapper.updateById(queue) > 0;
    }

    @Override
    public boolean cancelTask(Long taskId, String cancelReason) {
        // 查询待执行任务
        TaskExecutionQueue queue = taskExecutionQueueMapper.selectById(taskId);
        if (queue == null) {
            return false;
        }

        // 创建历史记录
        TaskExecutionHistory history = new TaskExecutionHistory();
        history.setId(queue.getId());
        history.setTaskName(queue.getTaskName());
        history.setSpringBeanName(queue.getSpringBeanName());
        history.setBizId(queue.getBizId());
        history.setTaskState(TaskExecutionHistoryStateEnum.CANCELLED.getCode()); // 设置为取消状态
        history.setFinishedTime(new Date());
        history.setAllowMaxErrorCount(queue.getAllowMaxErrorCount());
        history.setErrorCount(queue.getErrorCount());
        history.setErrorReason(cancelReason); // 记录取消原因
        // 确保 variable 字段始终有默认值
        if (queue.getVariable() != null && !queue.getVariable().isEmpty()) {
            history.setVariable(queue.getVariable());
        } else {
            history.setVariable("{}");
        }
        history.setCreateTime(queue.getCreateTime());
        history.setCreateUser(queue.getCreateUser());
        history.setUpdateTime(new Date());

        // 插入历史记录
        int result = taskExecutionHistoryMapper.insert(history);

        // 删除队列中的任务
        taskExecutionQueueMapper.deleteById(taskId);

        return result > 0;
    }


    @Override
    public boolean cancelTaskByBizId(Long bizId, String cancelReason) {
        List<TaskExecutionQueue> queues = taskExecutionQueueMapper.selectList(
                Wrappers.lambdaQuery(TaskExecutionQueue.class)
                        .eq(TaskExecutionQueue::getBizId, bizId)
        );
        if (!queues.isEmpty()) {
            for (TaskExecutionQueue queue : queues) {
                cancelTask(queue.getId(), cancelReason);
            }
            return true;
        }
        return false;
    }

    @Override
    public Integer incrementErrorCount(Long taskId) {
        TaskExecutionQueue queue = taskExecutionQueueMapper.selectById(taskId);
        if (queue != null) {
            int newErrorCount = queue.getErrorCount() + 1;
            queue.setErrorCount(newErrorCount);
            taskExecutionQueueMapper.updateById(queue);
            return newErrorCount;
        }
        return 0;
    }

    @Override
    public boolean archiveTaskToHistory(Long taskId, Integer finishedState, Date finishedTime) {
        // 查询待执行任务
        TaskExecutionQueue queue = taskExecutionQueueMapper.selectById(taskId);
        if (queue == null) {
            return false;
        }

        // 创建历史记录
        TaskExecutionHistory history = new TaskExecutionHistory();
        history.setId(queue.getId());
        history.setTaskName(queue.getTaskName());
        history.setSpringBeanName(queue.getSpringBeanName());
        history.setBizId(queue.getBizId());
        history.setTaskState(finishedState);
        history.setFinishedTime(finishedTime);
        history.setAllowMaxErrorCount(queue.getAllowMaxErrorCount());
        history.setErrorCount(queue.getErrorCount());
        history.setErrorReason(queue.getErrorReason());
        // 确保 variable 字段始终有默认值
        if (queue.getVariable() != null && !queue.getVariable().isEmpty()) {
            history.setVariable(queue.getVariable());
        } else {
            history.setVariable("{}");
        }
        history.setCreateTime(queue.getCreateTime());
        history.setCreateUser(queue.getCreateUser());
        history.setUpdateTime(new Date());

        // 插入历史记录
        int result = taskExecutionHistoryMapper.insert(history);

        // 删除队列中的任务
        taskExecutionQueueMapper.deleteById(taskId);

        return result > 0;
    }

    @Override
    public Long restoreTaskFromHistory(Long historyId, Integer newAllowMaxErrorCount) {
        // 查询历史记录
        TaskExecutionHistory history = taskExecutionHistoryMapper.selectById(historyId);
        if (history == null) {
            return null;
        }

        // 创建新的待执行任务
        TaskExecutionQueue queue = new TaskExecutionQueue();
        queue.setTaskName(history.getTaskName());
        queue.setSpringBeanName(history.getSpringBeanName());
        queue.setBizId(history.getBizId());
        queue.setAllowMaxErrorCount(newAllowMaxErrorCount != null ? newAllowMaxErrorCount : history.getAllowMaxErrorCount());
        queue.setTaskState(TaskExecutionQueueStateEnum.NOT_STARTED.getCode());
        queue.setErrorCount(0);
        queue.setErrorReason(null);
        // 确保 variable 字段始终有默认值
        if (history.getVariable() != null && !history.getVariable().isEmpty()) {
            queue.setVariable(history.getVariable());
        } else {
            queue.setVariable("{}");
        }
        queue.setCreateTime(history.getCreateTime());
        queue.setCreateUser(history.getCreateUser());
        queue.setUpdateTime(new Date());

        // 插入到队列中
        taskExecutionQueueMapper.insert(queue);

        return queue.getId();
    }

    @Override
    public List<TaskExecutionQueueDTO> getPendingTasks(Class<?> springBeanClass, Integer count) {
        LambdaQueryWrapper<TaskExecutionQueue> queryWrapper = new LambdaQueryWrapper<>();
        if(springBeanClass != null){
            String springBeanName = springBeanClass.getSimpleName();
            queryWrapper.eq(TaskExecutionQueue::getSpringBeanName, springBeanName);
        }
        queryWrapper.in(TaskExecutionQueue::getTaskState,
                TaskExecutionQueueStateEnum.NOT_STARTED.getCode(),
                TaskExecutionQueueStateEnum.FAILED_RETRY.getCode());
        queryWrapper.orderByAsc(TaskExecutionQueue::getId);
        IPage<TaskExecutionQueue> page = taskExecutionQueueMapper.selectPage(new Page<>(1, count, false), queryWrapper);
        return BeanUtil.copyToList(page.getRecords(), TaskExecutionQueueDTO.class);
    }
}
